package org.rency.mq.activemq.utils;

import com.alibaba.fastjson.JSON;
import org.rency.mq.activemq.constant.MessageFormat;
import org.rency.mq.activemq.request.MQRequest;
import org.rency.mq.activemq.request.NotifyRequest;

import javax.jms.*;
import java.io.Serializable;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

public class MessageConvert {

	public static Message toMessage(Session session, Object request, int messageFormat) throws JMSException {
		if (request instanceof Message) {
			return (Message) request;
		}
		
		if (request instanceof MQRequest) {
			MQRequest mqRequest = (MQRequest) request;
			
			if (messageFormat == MessageFormat.JSON) {
				return createTextMessage(session, JSON.toJSONString(request));
			}else if (messageFormat == MessageFormat.OBJECT) {
				return createObjectMessage(session, mqRequest);
			}else{ 
				NotifyRequest<?> notifyRequest = (NotifyRequest<?>) mqRequest;
				
				if(messageFormat == MessageFormat.TEXT){
					return createTextMessage(session, (String)notifyRequest.getContent());
				}else if(messageFormat == MessageFormat.MAP){
					return createMapMessage(session, (Map<?, ?>)notifyRequest.getContent());
				}else if(messageFormat == MessageFormat.BYTE_ARRAY){
					return createByteArrayMessage((byte[]) notifyRequest.getContent(), session);
				}
				
				throw new IllegalArgumentException("Invalid message type. Message support object, json and map.");
			}
		} else if (request instanceof String) {
			return createTextMessage(session, (String)request);
		}  else if (request instanceof byte[]) {
			return createByteArrayMessage((byte[]) request, session);
		} else if (request instanceof Map) {
			return createMapMessage(session, (Map<?, ?>)request);
		} else  if (request instanceof Serializable) {
			return createObjectMessage(session, (Serializable)request);
		} else {
			throw new IllegalArgumentException("Invalid message type. Message support object, json and map.");
		}
	}

	public static Object fromMessage(Message message) throws JMSException {
		if (message instanceof TextMessage) {
			return extractStringFromMessage((TextMessage) message);
		}
		else if (message instanceof BytesMessage) {
			return extractByteArrayFromMessage((BytesMessage) message);
		}
		else if (message instanceof MapMessage) {
			return extractMapFromMessage((MapMessage) message);
		}
		else if (message instanceof ObjectMessage) {
			return extractSerializableFromMessage((ObjectMessage) message);
		}
		else {
			return message;
		}
	}

	private static Message createTextMessage(Session session, String text) throws JMSException {
		TextMessage message = session.createTextMessage();
		message.setText(text);

		return message;
	}
	
	private static Message createByteArrayMessage(byte[] bytes, Session session) throws JMSException {
		BytesMessage message = session.createBytesMessage();
		message.writeBytes(bytes);
		return message;
	}

	private static Message createMapMessage(Session session, Map<?, ?> map) throws JMSException {
		MapMessage message = session.createMapMessage();
		
		for (Object key : map.keySet()) {			
			if (!(key instanceof String)) {
				throw new IllegalArgumentException("Cannot convert non-String key of type [" +
						key.getClass().getName() + "] to JMS MapMessage entry");
			}
			
			message.setObject((String) key, map.get(key));
		}
		return message;
	}

	private static Message createObjectMessage(Session session, Serializable object) throws JMSException {
		ObjectMessage objMessage = session.createObjectMessage();
		objMessage.setObject(object);

		return objMessage;
	}
	
	private static String extractStringFromMessage(TextMessage message) throws JMSException {
		return message.getText();
	}

	private static byte[] extractByteArrayFromMessage(BytesMessage message) throws JMSException {
		byte[] bytes = new byte[(int) message.getBodyLength()];
		message.readBytes(bytes);
		return bytes;
	}

	private static Map<String, Object> extractMapFromMessage(MapMessage message) throws JMSException {
		Map<String, Object> map = new HashMap<String, Object>();
		Enumeration<?> en = message.getMapNames();
		while (en.hasMoreElements()) {
			String key = (String) en.nextElement();
			map.put(key, message.getObject(key));
		}
		
		return map;
	}

	private static Serializable extractSerializableFromMessage(ObjectMessage message) throws JMSException {
		return message.getObject();
	}
}
